package org.tp8.sampleapp.view;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedProperty;
import javax.faces.context.FacesContext;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.bson.types.ObjectId;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile;
import org.tp8.sampleapp.dms.model.Attachment;
import org.tp8.sampleapp.dms.model.BaseDocModel;
import org.tp8.sampleapp.enums.CRUDAction;
import org.tp8.sampleapp.exc.SampleAppException;
import org.tp8.sampleapp.util.SampleAppLogger;
import org.tp8.sampleapp.view.util.SessionConstants;
import org.tp8.sampleapp.view.wrapper.AttachmentWrapper;

/**
 * The Class AbstractDocBean.
 * 
 * @param <T>
 *            the generic type
 */
public abstract class AbstractDocBean<T extends BaseDocModel> extends
		AbstractBean {

	/** The Constant log. */
	private final static SampleAppLogger log = new SampleAppLogger(
			AbstractDocBean.class);

	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = 5615075402665760439L;

	/**
	 * The item.
	 */
	private T item;

	/**
	 * The id.
	 */
	@ManagedProperty("#{param.id}")
	private String id;

	/**
	 * Gets the item.
	 * 
	 * @return the item
	 */
	public T getItem() {
		// If item is empty
		if (item == null) {
			// Check if id has been specified
			if (StringUtils.isNotBlank(id)) {
				// and load
				item = findOne(id);
			} else {
				// instead create new
				item = createNew();
			}
		}
		return item;
	}

	/**
	 * Handle file upload.
	 * 
	 * @param event
	 *            the event
	 */
	public void handleFileUpload(FileUploadEvent event) {
		UploadedFile file = event.getFile();

		FacesMessage msg = null;
		byte[] content = null;
		InputStream is = null;
		try {
			is = file.getInputstream();
			content = IOUtils.toByteArray(is);
		} catch (IOException e) {
			log.error(e);
			msg = new FacesMessage("Error uploading ", file.getFileName() + ".");
		} finally {
			IOUtils.closeQuietly(is);
		}

		if (content != null) {
			try {
				processFileUpload(file.getFileName(), content,
						file.getContentType());
				msg = new FacesMessage("Successful", file.getFileName()
						+ " is uploaded.");
			} catch (SampleAppException exc) {
				log.error("Error while processing file: " + file.getFileName(),
						exc);
				msg = new FacesMessage("Error uploading ", file.getFileName()
						+ ".");
			}
		}

		FacesContext.getCurrentInstance().addMessage(null, msg);
	}

	/**
	 * Process file upload.
	 * 
	 * @param filename
	 *            the filename
	 * @param content
	 *            the content
	 * @param mimetype
	 *            the mimetype
	 * @throws SampleAppException
	 *             the sample app exception
	 */
	public abstract void processFileUpload(String filename, byte[] content,
			String mimetype) throws SampleAppException;

	/**
	 * Sets the item.
	 * 
	 * @param item
	 *            the new item
	 */
	public void setItem(T item) {
		this.item = item;
	}

	/**
	 * Gets the id.
	 * 
	 * @return the id
	 */
	public String getId() {
		return id;
	}

	/**
	 * Sets the id.
	 * 
	 * @param id
	 *            the new id
	 */
	public void setId(String id) {
		this.id = id;
	}

	/**
	 * Gets the item id.
	 * 
	 * @return the item id
	 */
	public String getItemId() {
		ObjectId bbjId = getItem().getId();
		String id = null;
		if (bbjId != null) {
			id = bbjId.toString();
		}
		return id;
	}

	/**
	 * Sets the item id.
	 * 
	 * @param id
	 *            the new item id
	 */
	public void setItemId(String id) {
		ObjectId objId = ObjectId.massageToObjectId(id);
		getItem().setId(objId);
	}

	/**
	 * Gets the attachment.
	 * 
	 * @param id
	 *            the id
	 * @return the attachment
	 * @throws IOException
	 * @throws SampleAppException
	 *             the sample app exception
	 */
	public Attachment getAttachment(String id) throws IOException {
		AttachmentWrapper wrapper = (AttachmentWrapper) getSessionMap().get(
				SessionConstants.ΒΟΟΚ_UPLOADED_ATTACHMENT);
		Attachment attachment;

		if (wrapper == null) {
			attachment = null;
		} else if (CRUDAction.INSERT.equals(wrapper.getAction())
				|| CRUDAction.UPDATE.equals(wrapper.getAction())) {
			attachment = wrapper.getAttachment();
		} else if (CRUDAction.DELETE.equals(wrapper.getAction())) {
			return null;
		} else {
			throw new RuntimeException("Unexpected CRUDAction: "
					+ wrapper.getAction());
		}

		if (attachment == null) {
			if (StringUtils.isEmpty(id)) {
				ObjectId objId = getItem().getAttachmentId();
				id = String.valueOf(objId);
			}

			attachment = getBookFacade().getAttachment(id);
		}

		return attachment;
	}

	/**
	 * Clear attachment.
	 * 
	 * @param delete
	 *            the delete
	 */
	public abstract void clearAttachment(boolean delete);

	/**
	 * Creates the new.
	 * 
	 * @return the t
	 */
	protected abstract T createNew();

	/**
	 * Find one.
	 * 
	 * @param id
	 *            the id
	 * @return the t
	 */
	protected abstract T findOne(String id);

	/**
	 * Find all.
	 * 
	 * @return the collection
	 */
	public abstract Collection<T> findAll();

	/**
	 * Delete.
	 * 
	 * @param id
	 *            the id
	 */
	public abstract void delete(String id);

}
